using System;
using System.Collections.Generic;
using System.Xml;
using System.IO;

using Sce.Pss.Core;
using Sce.Pss.Core.Environment;
using Sce.Pss.Core.Graphics;
using Sce.Pss.Core.Input;
using Sce.Pss.HighLevel.Model;
using UTFramework;

namespace CameraTest
{
 	public class AppMain
 	{
  		private static GraphicsContext graphics;
  		private static BasicModel model0;
		private static BasicModel model1;
		//private static BasicModel model2;
		//private static BasicModel model3;
		//private static BasicModel model4;
		//private static BasicModel model5;
		private static BasicModel model6;
		private static BasicModel player;
  		private static BasicProgram program;

		private static float cameraAngleSpeed = 1.0f;
		private static float cameraMoveSpeed = 0.5f;
  		
		private static Camera cam;
		private static Frustum _frust;
		
  		public static void Main (string[] args)
  		{
   			Initialize ();

   			while (true) {
    			SystemEvents.CheckEvents ();
    			Update ();
    			Render ();
   			}
  		}

 		public static void Initialize ()
  		{
   			// Set up the graphics system
   			graphics = new GraphicsContext ();
			
			
			
   			program = new BasicProgram();
			player = new BasicModel("/Application/model1.mdx",0);
			
   			model0 = new BasicModel("/Application/0.mdx",0);
			model1 = new BasicModel("/Application/1.mdx",0);
			model6 = new BasicModel("/Application/6.mdx",0);
			
			cam = new Camera();
			cam.Position_Camera(new Vector3(0,6,-15), new Vector3(0,3,0), new Vector3(0,1,0));//0, 6, -15, 0, 3, 0, 0, 1, 0);
			
			_frust = new Frustum(cam,graphics);
			
			string xmlPath = "/Application/XML/Hero.xml";
			ReadMyXMLDocument(xmlPath);
  		}
		
		public static void ReadMyXMLDocument(string filepath)  
		{  
		    string name, bbType;
			Vector3 hPosition;
			Vector3 hAngle;
			int id;
			float radius;
			
			
		    XmlDocument xd = new XmlDocument();  
			
		    FileStream fs = new FileStream(filepath, FileMode.Open);  
		    xd.Load(fs);  
		  
		    XmlNodeList heroList = xd.GetElementsByTagName("Hero");
			
		    for (int i = 0; i < heroList.Count; i++)  
		    {  
		        XmlElement hero = (XmlElement)xd.GetElementsByTagName("Hero")[i];         
		        XmlElement position = (XmlElement)xd.GetElementsByTagName("Position")[i];      
		        XmlElement angle = (XmlElement)xd.GetElementsByTagName("Angle")[i];   
		        XmlElement bBox = (XmlElement)xd.GetElementsByTagName("BBox")[i]; 
				
				#region hero tag
		        if (hero.GetAttribute("id") != null)  
		        {  
					id = Convert.ToInt32(hero.GetAttribute("id"));
		        }  
				
				if (hero.GetAttribute("name") != null)  
		        {  
					name = hero.GetAttribute("name");
		        }
				#endregion
				
				#region position tag
				if (position.GetAttribute("X") != null)  
		        {  
					hPosition.X = (float)Convert.ToDouble(position.GetAttribute("X"));
		        }
				
				if (position.GetAttribute("Y") != null)  
		        {  
					hPosition.Y = (float)Convert.ToDouble(position.GetAttribute("Y"));
		        }
				
				if (position.GetAttribute("Z") != null)  
		        {  
					hPosition.Z = (float)Convert.ToDouble(position.GetAttribute("Z"));
		        }
				#endregion
				
				#region angle tag
				if (angle.GetAttribute("X") != null)  
		        {  
					hAngle.X = (float)Convert.ToDouble(angle.GetAttribute("X"));
		        }
				
				if (angle.GetAttribute("Y") != null)  
		        {  
					hAngle.Y = (float)Convert.ToDouble(angle.GetAttribute("Y"));
		        }
				
				if (angle.GetAttribute("Z") != null)  
		        {  
					hAngle.Z = (float)Convert.ToDouble(angle.GetAttribute("Z"));
		        }
				#endregion
				
				#region bBox tag
				if (bBox.GetAttribute("Radius") != null)  
		        {  
					radius = (float)Convert.ToDouble(bBox.GetAttribute("Radius"));
		        }
				
				if (bBox.GetAttribute("type") != null)  
		        {  
					bbType = bBox.GetAttribute("type");
		        }
				#endregion
		    }  
		    // Закрываем поток  
		    fs.Close();  
		}
		
  		public static void Update ()
  		{
			cam.update();
   			// Query gamepad for current state
   			var gamePadData = GamePad.GetData (0);
			
			// Arrows
   			if((gamePadData.Buttons & GamePadButtons.Up) != 0)
			{
				cam.Move_Camera(cameraMoveSpeed);
			}
					
   			if((gamePadData.Buttons & GamePadButtons.Down) != 0)
			{
   				cam.Move_Camera(-cameraMoveSpeed);
			}
			
   			if((gamePadData.Buttons & GamePadButtons.Left) != 0)
			{
				cam.Strafe(-cameraMoveSpeed);
			}
			
   			if((gamePadData.Buttons & GamePadButtons.Right) != 0)
			{
				cam.Strafe(cameraMoveSpeed);
			}
   
			// Cross,Triangle,Circle,Square
			if((gamePadData.Buttons & GamePadButtons.Cross)!=0)
			{
				cam.Rotate_PositionX(cameraAngleSpeed);
				//cam.Rotate_Position(cameraAngleSpeed,1,0,0);
			}
			   
			if((gamePadData.Buttons & GamePadButtons.Triangle)!=0)
			{
				cam.Rotate_PositionX(-cameraAngleSpeed);
				//cam.Rotate_Position(-cameraAngleSpeed,1,0,0);
			}
			
			if((gamePadData.Buttons & GamePadButtons.Circle)!=0)
			{
				cam.Rotate_Position(cameraAngleSpeed,0,1,0);
			}
			   
			if((gamePadData.Buttons & GamePadButtons.Square)!=0)
			{
				cam.Rotate_Position(-cameraAngleSpeed,0,1,0);
			}
			
			// Shifts
			if((gamePadData.Buttons & GamePadButtons.L) != 0)
			{	
				//cam.Move_CameraY(cameraMoveSpeed);
				cam.upDown(cameraMoveSpeed);
			}
			
   			if((gamePadData.Buttons & GamePadButtons.R) != 0)
			{	
				//cam.Move_CameraY(-cameraMoveSpeed);
				cam.upDown(-cameraMoveSpeed);
			}
			
			// Zoom
			if ((gamePadData.Buttons & GamePadButtons.Start) != 0)
			{
				cam.zoom_View(0.1f);
			}
			
			if ((gamePadData.Buttons & GamePadButtons.Select) != 0)
			{
				cam.zoom_View(-0.1f);
			}
			
			
			// Stiks
			if ((gamePadData.AnalogRightX>0.1f)||(gamePadData.AnalogRightX<-0.1f))
			{
				cam.Rotate_Position(gamePadData.AnalogRightX,0,1,0);
			}
			
			if ((gamePadData.AnalogRightY>0.1f)||(gamePadData.AnalogRightY<-0.1f))
			{
				cam.Rotate_PositionX(gamePadData.AnalogRightY);
			}
			
			if ((gamePadData.AnalogLeftY>0.1f)||(gamePadData.AnalogLeftY<-0.1f))
			{
				cam.Move_Camera(-gamePadData.AnalogLeftY);	
			}
			
			if ((gamePadData.AnalogLeftX>0.1f)||(gamePadData.AnalogLeftX<-0.1f))
			{
				cam.Strafe(gamePadData.AnalogLeftX);
			}
			
			
			_frust.Calculate();
  		}

  		public static void Render ()
  		{
   			// Clear the screen
			// Graphis settings
   			graphics.SetClearColor (1.0f, 1.0f, 1.0f, 0.0f);
   			graphics.Clear ();
   
   			Matrix4 projectionMatrix = Matrix4.Perspective(FMath.Radians(45.0f+cam.getZoom()),graphics.Screen.AspectRatio, 1.0f, 250.0f);
   			Matrix4 viewMatrix = cam.LookAt();
   
   
   			Vector3 litDirection = new Vector3( 0.5f, -1.0f, -1.0f ).Normalize();
   			Vector3 litColor = new Vector3( 0.0f, 0.0f, 1.0f );
   
   			BasicParameters parameters = program.Parameters;
   			parameters.Enable(BasicEnableMode.Lighting, true);
			
   			parameters.SetViewMatrix(ref viewMatrix);
   			parameters.SetLightCount(1) ;
   			parameters.SetLightDirection(0, ref litDirection);
   			parameters.SetLightDiffuse( 0, ref litColor);
   			parameters.SetLightSpecular(0, ref litColor);
   
   			parameters.SetProjectionMatrix(ref projectionMatrix);
			
   			graphics.SetViewport(0,0,graphics.Screen.Width,graphics.Screen.Height );
   			graphics.Enable(EnableMode.Blend);

   			graphics.Enable(EnableMode.CullFace) ;
   			graphics.SetCullFace(CullFaceMode.Back, CullFaceDirection.Ccw) ;
   
   			graphics.Enable(EnableMode.DepthTest);
   			graphics.SetDepthFunc(DepthFuncMode.LEqual, true);
			
			// Models
   			Matrix4 world = Matrix4.Identity;
			
   			model0.SetWorldMatrix(ref world);
   			model0.Update();
   			model0.Draw(graphics,program);
   
			model1.SetWorldMatrix(ref world);
   			model1.Update();
   			model1.Draw(graphics,program);
			
			model6.SetWorldMatrix(ref world);
   			model6.Update();
   			model6.Draw(graphics,program);
			
			// Player
			Matrix4 plPos;
			plPos = Matrix4.Translation(cam.getViewX(),cam.getViewY()-2,cam.getViewZ());
			
			Matrix4 plRot = Matrix4.Identity;
			plRot = Matrix4.RotationXyz(0.0f,FMath.Radians(cam.getAngleY()),0.0f);
   			
			Matrix4 plMatrix = plPos*plRot;
				
			player.WorldMatrix = plMatrix;
			player.Update();
			player.Draw(graphics,program);
			
			
   			graphics.SwapBuffers ();

   			graphics.Disable(EnableMode.CullFace);
   			graphics.Disable(EnableMode.DepthTest);
  		}
 	}
}